메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

PyXML 개론

한빛미디어

|

2002-11-26

|

by HANBIT

9,917

저자: 우체 옥버지(Uche Ogbuji), 역 전순재

아마 여러분도 이전 칼럼(파이썬과 XML의 예술적인 만남)의 파이썬 소프트웨어 표에서 짐작했겠지만, 상당수의 XML 처리용 파이썬 도구들을 PyXML 패키지에서 얻을 수 있다. 물론 파이썬 안으로 구축되어 들어간 XML 라이브러리도 있지만, 이 라이브러리들은 공식 문서에서 아주 잘 다루고 있다.

재미있는 일...

이 컬럼을 통해 필자가 하고 싶은 일 중에 하나는 중요한 소프트웨어 배포를 비롯하여, 파이썬-XML 개발에 대한 새롭고도 중요한 소식들과 관련된 간략한 정보를 제공하는 것이다.

PyXML 0.8.1이 배포되었다. 중요 변화는 갱신된 DOM 지원이 포함되었고 그리고 함께 배포되는(bundled) XSLT 라이브러리를 기본 설정에서 불능으로 설정할 수 있게 되었다는 것이다. 더 자세한 PyXML 정보는 아래에 있다.

프레드릭 "에프보드" 룬트(Fredrik "effbot" Lundh)는 파이썬으로 그래픽 RSS 뉴스 리더(newsreader)를 개발하는 프로젝트를 시작하였다. 또한 마크 노팅햄(Mark Nottingham)은 RSS.py를 개발했는데, 이 모듈은 RSS 0.9.x와 1.0의 피드(feeds)을 처리하기 위한 파이썬 모듈이다. 마크(Mark)는 RSS 튜토리얼의 저자이다.

에릭 프리스(Eric Freese)는 SemanText를 배포하였는데, 이 프로그램은 XML Topic Maps를 사용하여 의미구조적 네트워크를 개발하고 관리한다. 또 그러한 topic maps를 상황에 맞게 일반적인 XML 포맷으로부터 구축할 수도 있다. 여기에는 지식기반 관리를 위한 구이(GUI)가 함께 따라온다.

그동안 XML-SIG에서는 데이터 형들을 스키마(schema) 안으로 끼워넣는 데 유용한 일반적 형태의 라이브러리 골격구조를 파이썬으로 개발하는데 관한(웹 서비스와 다른 프로젝트들) 논의가 계속해서 진행되어 오고 있었다.

마지막으로, 이전 컬럼에서 필자는 cDomlette XML 파서가 XInclude와 XML Base를 지원한다고 언급했지만, libxml 파서 역시 그럴 수 있다는 점은 언급하지 않았다. libxml도 XML Catalogs를 지원한다. 또한 xmlproc도 XML catalogs를 지원한다. 최근에 구축된 4Suite과 XML, OASIS catalog는 cDomlette를 지원한다.


Python & XML

참고 도서

Python & XML
Fred L. Drake, Jr. / Christopher A. Jones


PyXML 설정하기

PyXML은 소스 형태, 윈도우 설치기, RPM 형태로 사용할 수 있다. 갖추어야 할 필수 조건은 오직 파이썬 하나만 있으면 된다. 어느 버전이라도 2.0 이후면 문제없다. 그렇지만 필자는 2.2.1 이나 그 이후를 권장한다. 운영 환경에 C 컴파일러가 구비되어 있으면 소스에서 구축하는 것이 편리하다. 압축파일을 내려받아, 적당한 위치에 풀어 놓고 다음을 실행하자.
python setup.py install
이렇게 하는 것이 파이썬 프로그램을 설치하는 일반적인 방법이다. 이것은 설치 명령어를 실행하느라 사용된 파이썬 실행파일이 있는 패키지 디렉토리에 자동으로 설치된다. 파일들을 컴파일하고 복사하면 수 많은 출력결과들을 보게 될 것이다. 이것을 억제하는게 좋겠다 싶으면, "python setup.py --quiet install"을 사용하자.

PyXML은 파이썬에 따라오는 xml 모듈을 덮어써서 파이썬 모듈의 모든 내용들을 자신의 버전으로 대체한다. 두 코드 기반이 동일하기 때문에 대개의 경우 이것은 특별히 문제 되지 않는다. PyXML이 기능과 버그 수정이 조금 더 이루어 졌다는 점만 빼고 말이다. PyXML에서 새로운 버그가 도출될 수도 있다. PyXML을 삭제하고 싶으면, 파이썬 설치 디렉토리의 "site-packages" 디렉토리에서 "_xmlplus" 디렉토리를 지우기만 하면 된다. 원래의 파이썬 xml 모듈은 그대로 남아 있을 것이다.

SAX

PyXML의 SAX 지원은 파이썬에 내장된 SAX 라이브러리와 기본적으로 같은 코드이다. 추가된 주요 특징은 정말 똑똑한 모듈인 xml.sax.writers로서, 이 모듈은 SAX 사건을 XML이나 심지어 SGML로 재직렬화(re-serializing)하는 기능을 제공한다. 이 모듈은 SAX 필터 체인(filter chain)[1]의 마지막 지점으로 특히 쓸모가 있다. 그리고 이에 대해서는 앞으로 파이썬 SAX 필터(filters)기에 관한 기사에서 더 자세하게 다루어 보겠다. PyXML에는 xmlproc이라는 유효성검사 XML 해석기가 추가되어 있는데 make_parser 함수를 사용하면 선택할 수 있다. 기본 파이썬은 유효성 검사를 지원하지 않는다.

DOM

PyXML은 파이썬에 함께 따라오는 DOM 노드 클래스의 골격 위에 상당량의 구조물을 세웠다. 무엇보다도 4DOM이 있다. 이 커다란 DOM 구현은 자연스럽게 파이썬적이 되려고 하기 보다는 DOM 규격을 더욱 잘 준수하려고 노력한다. 4DOM은 XML (코어) 그리고 HTML 모듈 모두에서 DOM Level 2를 지원하며, 여기에는 사건(events), 범위(ranges), 순회(traversal)가 포함된다. PyXML은 minidom과 pulldom을 자주 갱신하여 제공한다. 수 많은 DOM 구현이 파이썬용으로 사용이 할 수 있기 때문에 PyXML 또한 원하는 기능에 맞추어 구현을 선택하기 위해 시스템을 xml.dom.domreg에 추가한다. 현재로서는 minidom과 4DOM 만이 등록되어 있다. 그래서 아직까지 일반적으로 쓸모가 있는 것은 아니지만 이 상황은 조만간 바뀔 것으로 예측된다. xml.dom.ext 모듈에도 많은 재료들이 있지만, PyXML에 종속적인 DOM 확장이기 때문에 일반적으로 제외된다. 이 확장에는 DOM Level 3에서 앞으로 제공할, 직렬화된 XML을 읽고 쓰는 메커니즘이 미리 포함되어 있다.

4DOM 노드를 생성하는 것은 xml.dom.ext.readers 안에 존재하는 모듈들을 사용하는 문제와 관련이 있다. 일반적인 패턴은 판독 객체를 하나 만드는 것이다. 그리고 나면 이 판독 객체를 여러 소스로부터 해석하는데 사용할 수 있다. XML을 해석하는 데는 보통 xml.dom.ext.readers.Sax2를 사용하려 하고, HTML을 해석하는 데는 xml.dom.ext.readers.HtmlLib을 사용하고 싶을 것이다. 목록 1은 XML을 읽는 방법을 시연한다.

목록 1: 한 문자열에서 XML을 읽어서 4DOM 노드 하나를 만들기
from xml.dom.ext.reader import Sax2

DOC = """

  Christopher Okibgo
  For he was a shrub among the poplars, 
  Needing more roots
  More sap to grow to sunlight, 
  Thirsting for sunlight

"""

# XML 판독 객체를 만들어라
reader = Sax2.Reader()
# 한 문자열에서 XML로부터 해석된 4DOM 문서 노드 하나를 만들어라
doc_node = reader.fromString(DOC)

# 문서 노드에서 통상적인 DOM 연산을 실행할 수 있다
verse_element = doc_node.documentElement
# 게다가 노드 리스트(Node lists) 그리고 이름있는 노드 맵(named node maps)과 같은 것들을 위한
# "파이썬적인" 지름길도 사용할 수 있다.
# verse 요소의 첫 번째 자손은 공백 텍스트 노드이다
# 두 번째 자손은 attribution 요소이다
attribution_element = verse_element.childNodes[1]
# attribution_string은 "Christopher Okibgo"이 된다
attribution_string = attribution_element.firstChild.data
목록 2는 HTML를 읽는 방법을 시연한다. 인터넷에 접속되어 있어야 성공적으로 실행할 수 있다.

목록 2: URL로부터 읽어서 4DOM HTML 노드 하나를 만들기
from xml.dom.ext.reader import HtmlLib

# HTML 판독 객체를 하나 만들어라
reader = HtmlLib.Reader()
# URL에 위치한 HTML에서 해석된 4DOM 문서를 하나 만들어라
doc_node = reader.fromUri("http://www.python.org")

# 그 HTML 문서의 제목을 취하라
title_elem = doc_node.documentElement.getElementsByTagName("TITLE")[0]
# title_string은 "Python Language Website"가 된다
title_string = title_elem.firstChild.data
HTML 해석기(parser)는 매우 관용적이지만, 대부분의 웹 브라우저가 다 그런 것은 아니다. 어떤 비표준 HTML은 에러를 일으킬 수도 있다.

xml.dom.ext.Print와 xml.dom.ext.PrettyPrint 함수를 사용하면 XML로도 출력할 수 있다. 또한 xml.dom.ext.XHtmlPrint과 xml.dom.ext.XHtmlPrettyPrint를 사용하면 적절한 XML과 HTML DOM 노드로부터 적당한 XHTML을 출력할 수 있다. 요소들 사이에 있는 순수한 공백 노드들은 xml.dom.ext.StripXml과 xml.dom.ext.StripHtml를 사용해서 삭제할 수 있다. 이 모듈에는 이것들 말고도 다른 자잘한 유틸리티가 있다. 목록 3은 목록 1에 계속되는 것으로, 읽은 문서를 취해 공백을 제거한 후 그 결과를 XML로 재직렬화한다.

by Uche Ogbuji

목록 3: 공백을 제거하고 그 결과를 XML로 쓰기
from xml.dom.ext import StripXml, Print
# 적절한 장소에서 공백을 제거하고 같은 노드를 반환하라
StripXml(doc_node)
# 직렬화된 XML 노드를 표준출력(stdout)에 써라
Print(doc_node)
# 직렬화된 XML 노드를 파일에 써라
f = open("tmp.xml", "w")
Print(doc_node, stream=f)
f.close()
목록 4는 표준 DOM API를 사용하여 무에서부터(from scratch) 작은 XML 문서를 만들고, 직렬화된 그 결과를 인쇄하는 방법을 시연한다.

목록 4: 조금씩 4DOM 문서를 만들면서 그 결과를 쓰기
from xml.dom import implementation
from xml.dom import EMPTY_NAMESPACE, XML_NAMESPACE
from xml.dom.ext import Print

# doctype 이름으로 "message"를 사용하여 문서 형 노드 하나를 만들어라 
# 빈 시스템ID(system ID)와 빈 공개ID(public ID) (즉, DTD 정보 없음)
doctype = implementation.createDocumentType("message", None, None)

# 문서 노드를 작성하라, 이 문서 노드는 또한 문서 요소 노드 하나를 만든다
# 그 문서 요소에 대하여, 빈 네임스페이스 URI와 그리고 지역적 이름으로 "message"를 사용하라
doc = implementation.createDocument(EMPTY_NAMESPACE, "message", doctype)

# 문서 요소를 확보하라
msg_elem = doc.documentElement

# 새 요소에 xml:lang 속성을 만들어라
msg_elem.setAttributeNS(XML_NAMESPACE, "xml:lang", "en")

# 약간의 내용을 구비한 텍스트 노드 하나를 만들어라
new_text = doc.createTextNode("You need Python")

# 새로운 텍스트 노드를 문서 요소에 추가하라
msg_elem.appendChild(new_text)

# 그 결과를 인쇄하라
Print(doc)
빈 URI와 ID 필드(fields)[2]에 대하여 EMPTY_NAMESPACE이나 None을 사용한 것을 주목하자. 이것은 Python-XML의 관례이다. 빈 문자열을 사용하기보다(역시 이것이 유효한 URI 참조이지만), None이 사용된다(EMPTY_NAMESPACE는 단지 None에 대한 별명일 뿐이다). 이렇게 하면 좀 더 쉽게 읽을 수 있다는 이점이 추가된다. 이것을 실행하면, XML 네임스페이스에 어떤 선언도 없는 것을 볼 것이다. 이것은 그 네임스페이스의 특수한 상태 때문이다. 다른 네임스페이스에 요소나 속성을 만들면, 그러한 네임스페이스 선언들은 출력할 때 가공처리 될 것이다.

4DOM은 일반적으로 DOM을 배우는 데에는 유용한 도구이지만 대부분의 경우에서는 실용적인 DOM이 아니다. 왜냐하면 4DOM이 몹시 느리고 메모리를 혹사하기 때문이다. 그래서 DOM의 비밀을 처리하는데 엄청난 노력이 들어가고 있다. 특히, 사건처리 시스템(event system)은 비록 아주 흥미로운 사용법들을 갖추고는 있지만 성능을 느리게 만드는 중대한 요인이다. 필자도 원래 4DOM 저작자 중의 한 명이지만, 이제는 거의 사용하지 않는다. 다른, 더욱 빠른 DOM 구현들이 있기 때문이다. 필자는 이러한 것을을 앞으로 컬럼에서 다루어 볼 생각이다. 다행스럽게도 4DOM으로 실험해 보면서 배운 교훈들은 다른 파이썬 DOM에도 거의 대부분 응용할 수 있다.

규격화(Canonicalization)

두 개의 XML 파일이 서로 다를 수 있지만, 그 내용이 한 XML에 처리기에 대하여 여전히 같은 효과를 가질 수 있다. 이것은 XML이 어떤 차이는 별로 심각하지 않다고 정의하기 때문이다. 예를 들어 속성들의 순서, 따옴표나 겹따옴표의 선택, 그리고 약간 다른 문자 개체의 사용법과 같은 차이말이다. 규격화(Canonicalization)는 보통 c14n으로 약자화 되는데 XML을 직렬화하는 메커니즘으로서 이러한 모든 차이점들을 표준화한다. 그렇게 하여 c14n를 사용하면 XML 파일을 더 쉽게 비교할 수 있다. 이것이 중요하게 응용되는 분야 하나는 보안이다. 혹시 XML 파일이 조작되지 않았다는 사실을 확증하는 데에 이 기술을 사용하고 싶을 수도 있겠지만 별거 아닌 구문적 차이들을 무시하는 데에도 이 점검을 이용하고 싶을 것이다. xml.dom.ext.c14n 모듈은 파이썬을 위한 규격화(Canonicalize) 기능을 제공하는데, 이 함수는 DOM 노드를 하나 취해서 (대부분의 구현이 작동하리라고 생각함) 규격화된 XML로 작성해 낸다.

XPath

PyXML에는 완전히 파이썬으로 작성된 XPath와 XSLT 구현이 포함되어 있다. 그렇지만 이 기사를 쓰는 시점에서 XSLT 모듈은 여전히 PyXML로 통합중이며 실제로는 작동하지는 않는다. XSLT 처리가 필요하다면 이전 설치 기사에서 언급한 Python-libxslt, 4Suite, Pyana, 또는 다른 패키지들 중의 하나가 필요할 것이다. 그렇지만 XPath 지원은 작동하며 DOM 노드를 연산처리 할 수 있다. 사실, XPath는 DOM 메소드를 사용하여 항해하는 데 아주 간편한 지름길로 사용될 수 있다. 다음 스니펫(snippet)은 XPath 표현식을 사용하여 XSLT 네임스페이스에 존재하는 한 DOM 문서 내에 있는 모든 요소들의 목록을 열람한다. 이 스니펫을 실행해보고 싶으면 먼저 "doc"을 DOM 문서 노드 객체로 정의하도록 코드를 준비하면 된다.
from xml.ns import XSLT
# XSLT 네임스페이스(namespace) http://www.w3.org/1999/XSL/Transform
NS = XSLT.BASE

from xml.xpath import Context, Evaluate
# 주어진 DOM 노드에 맞는 XPath 상황판(context)을 만들어라
# 상황판 리스트에 다른 노드들이 없다면
# (리스트 크기가 1, 현재 위치 1)
# 그리고 주어진 접두사/네임스페이스(prefix/namespace) 짝짓기(mapping)
con = Context.Context(doc, 1, 1, processorNss={"xsl": NS})

# XPath 표현식을 평가해서 그 결과를 반환하라
# 노드들을 담은 파이썬 리스트
result = Evaluate("//xsl:*", context=con)
XPath 표현식(expressions)은 다른 데이터 형을 반환할 수도 있다. 문자열(strings), 숫자(numbers), 불리언(boolean)이 그 형태이다. 문자열과 숫자는 통상적인 파이썬 문자열(strings)과 부동소수(floats)로 반환된다. 그렇지만 불리언(Booleans)은 xml.utils.boolean이라는 특수 클래스의 실체로 반환된다. 이것은 아마도 파이썬 2.3에서 변경될 것이다. 파이썬 2.3은 내장 불리언(boolean) 형을 갖추고 있다.

광범위하게 XPath를 이용할 생각이라면 4Suite에 있는 구현도 역시 고려하고 있을 것이다. 이 구현이 PyXML에 있는 것보다 더 빠른 버전이며, 버그도 더 많이 수정되었다.

기타 등등

지난 설치기사에서 PyXML에 있는 다른 모듈들 몇 개를 언급하였다. 여기에는 xml.parsers.xmlproc 모듈에 있는 xmlproc 유효성 검사 해석기와 xml.utils.qp_xml에 있는 XML 퀵 파서(Quick Parsing for XML), xml.marshal.wddx 모듈의 WDDX 라이브러리가 포함된다. 마샬링(Marshalling)은 임의의 파이썬 객체를 XML로 표현하는 처리과정인데, 일반적인 마샬링 기능이 xml.marshal.generic 모듈에 역시 구비되어 있다. 표준 pickle(절임)모듈과 비슷한 인터페이스를 가지고 있다. 목록 6은 소형 파이썬 사전을 XML로 정돈(marshals)한다.

목록 6: 총괄 marshaling(정돈) 모듈로 실험하기
from xml.marshal.generic import Marshaller
marshal = Marshaller()
obj = {1: [2, 3], "a": "b"}
# 문자열로 쏟아부어라(Dump)
xml_form = marshal.dumps(obj)
생성된 XML은 다음과 같이 생겼다 (이해를 돕기 위해 줄내려쓰기와 들여쓰기가 추가됨):


  
    1
    23
    a
    b
  

포장하기

PyXML 패키지의 데모 디렉토리에 가면 더욱 많은 코드 샘플들을 볼 수 있다. 문제를 보고하거나 PyXML을 논의할 장소는 파이썬 XML 동호회 메일링 리스트이다.

다음 기사에서는 4Suite를 한 번 돌아 보겠다. 이 패키지는 개선된 버전의 PyXML의 기능들을 제공할 뿐만 아니라 다른 독특한 특징 역시 제공한다.


각주
[1] 한 소스가 여러 여과기를 거쳐 마지막에 이르면 소스 변환이 끝나고, 변환이 끝나면 파일로 써야 한다.
[2] 값이 할당되는 장소, 상황에 따라 변수(variable-기능적 프로그래밍), 필드(field-구조적 프로그래밍), 속성(attribute-객체지향 프로그래밍)으로 표현된다.

참고 기사: 파이썬과 XML의 예술적인 만남
TAG :

이전 글 : Message-Driven Bean

다음 글 : SVG의 현재 위치

댓글 입력
자료실

최근 본 책0